package com.wzdigit.wms.wms.service.transfer;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicDataItemDetailApi;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.mes.basic.dto.DataItemDetailDTO;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.transfer.*;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.transfer.*;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.basic.Warehouse;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.mid.IfTransferDtl;
import com.wzdigit.wms.basic.domain.mid.IfTransferHeader;
import com.wzdigit.wms.basic.domain.transfer.TransferDtl;
import com.wzdigit.wms.basic.domain.transfer.TransferHeader;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.enums.transfer.IfTransferDtlProcessStatusEnum;
import com.wzdigit.wms.basic.enums.transfer.IfTransferProcessStatusEnum;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.mapper.core.basic.WarehouseMapper;
import com.wzdigit.wms.basic.mapper.core.mid.IfTransferDtlMapper;
import com.wzdigit.wms.basic.mapper.core.mid.IfTransferHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.InvZoneMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferDtlMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.TransferHeaderMapper;
import com.wzdigit.wms.basic.util.DateUtils;
import com.wzdigit.wms.common.utils.DozerUtils;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.common.entity.StatusCode;
import com.wzdigit.wms.wms.service.basic.WarehouseService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * OMS调拨任务拆分（调拨中间表管理）-pc
 * @author Administrator
 *
 */
@Service
public class IfTransferManageService {
	
	@Autowired
	private IfTransferHeaderMapper ifTransferHeaderMapper;
	
	@Autowired
	private IfTransferDtlMapper ifTransferDtlMapper;
	
	@Autowired
	private TransferHeaderMapper transferHeaderMapper;
	
	@Autowired
	private TransferDtlMapper transferDtlMapper;
	
	@Autowired
    private WarehouseMapper warehouseMapper;
	
	@Autowired
	private InvZoneMapper invZoneMapper;
	
	@Autowired
	private SkuMapper skuMapper;
	
	@Autowired
    private LotnoService lotnoService;
	
	@Autowired
	private WarehouseService warehouseService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
	private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	@Reference(version = "${dubbo.consumers.basic.data.item.detail.api:1.0.0}", check = false, timeout = 300000)
    private BasicDataItemDetailApi basicDataItemDetailApi;
	
	@Value(value = "${default_owner.code}")
	private String DEFAULT_OWNER;

	@Value(value = "${default_owner.name}")
	private String DEFAULT_OWNER_NAME;
	
	/**
	 * 调拨中间表列表
	 * @param dto
	 * @return
	 * 【拆单按钮状态控制】：
	 * 1、所有明细均已分库，且“已拆单”=否的情况下可用，其它情况下不可用
	 */
	public PagerInfo<List<IfTransferManageResponse>> searchIfTransferManage(
			SearchIfTransferManageRequest dto, Pager<?> pager){
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<IfTransferManageResponse>> pagerInfo = new PagerInfo<>();
        
        Date beginDate = null, endDate = null;
        if(dto.getBeginTime() != null) {
        	beginDate = DateUtils.getStartTime(dto.getBeginTime());
        }
        if(dto.getEndTime() != null) {
        	endDate = DateUtils.getEndTime(dto.getEndTime());
        }
        if(dto.getTransferDeptName() != null) {
        	dto.setTransferDeptName(StringUtils.decode(dto.getTransferDeptName()));
        }
        List<IfTransferManageResponse> list = ifTransferHeaderMapper.getListIfTransferManage(dto, beginDate, endDate);
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	/**
	 * 调拨中间表明细
	 * @param transferHeaderId
	 * @return
	 * 【分库按钮状态控制】：
	 * 1、表头“已拆单”=否 ，且明细“已分库”=否 的情况下可用，其它情况下不可用
	 * 2、已分库：当前完成“分库”操作，或之前完成拆单操作后已生成调拨单的情况下，已分库=“是”
	 */
	public List<IfTransferManageDtlResponse> searchIfTransferManageDtl(
			Integer ifTransferHeaderId){
		return ifTransferDtlMapper.getListIfTransferManageDtl(ifTransferHeaderId);
	}
	
	/**
	 * 调拨单列表
	 * @param sourceNo
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<TransferManageListResponse>> searchTransferManage(
			String sourceNo, Pager<?> pager){
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<TransferManageListResponse>> pagerInfo = new PagerInfo<>();
        
		SearchTransferManageRequest dto = new SearchTransferManageRequest();
		dto.setSourceNo(sourceNo);
		
		List<TransferManageResponse> list = transferHeaderMapper.getListTransferManage(dto, 
				TransferManageService.transferTypeList, null, null);
		List<TransferManageListResponse> datas = DozerUtils.mapList(list, TransferManageListResponse.class);
		datas.forEach(one -> {
			one.setDtls(transferDtlMapper.getListTransferManageDtl(one.getTransferHeaderId()));
		});
		pagerInfo.setItems(datas);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	/**
	 * 获取可用库存
	 * @param ifTransferDtlId
	 * @return
	 */
	public List<AvailableInvZoneGroupWhsResponse> getAvailableInvZone(Integer ifTransferDtlId,
			HttpServletRequest servletRequest) {
		IfTransferDtl ifTransferDtl = ifTransferDtlMapper.selectById(ifTransferDtlId);
		if(IfTransferDtlProcessStatusEnum.YES.code == ifTransferDtl.getProcessStatus()) {
			Shift.fatal(StatusCode.NOTCAN_PREALOC);
		}
		
		// 查询当前用户权限仓库
		List<Integer> whsIdList = warehouseService.getWareHouseIds(servletRequest);
		
		// 无法匹配到批次号
		Lotno lotno = lotnoService.getLotnoByIfTransferDtlId(ifTransferDtlId, 0);
		if (lotno == null) {
			Shift.fatal(StatusCode.LOTNO_NULL);
		}
		
		SearchInvRequest dto = new SearchInvRequest();
		dto.setFactory(ifTransferDtl.getFromOrg());
        dto.setLotno(lotno.getLotno());
        dto.setSkuId(lotno.getSkuId());
        dto.setInvAttr(null);
        dto.setVendorId(null);
        dto.setQaStatus(null);
        
        List<AvailableInvZoneGroupWhsResponse> availableInvZoneGroupWhs = invZoneMapper.
        		getAvailableInvZoneGroupWhs(dto, whsIdList, WarehouseEnum.availableInvWhsTypeList);
		return availableInvZoneGroupWhs;
    }
	
	/**
	 * 确认分配库存
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<Integer> confirmInvZone(ConfirmInvZoneRequest dto,
			HttpServletRequest servletRequest) {
		// 调拨中间表明细
		IfTransferDtl ifTransferDtl = ifTransferDtlMapper.selectById(dto.getDtlId());
		if(IfTransferDtlProcessStatusEnum.YES.code == ifTransferDtl.getProcessStatus()) {
			Shift.fatal(StatusCode.NOTCAN_PREALOC);
		}
		
		// 检验：已分配数 = 需求数量
		int qty = 0;
		int transferQty = ifTransferDtl.getTransferQty().intValue();
		for (ConfirmInvZoneItemRequest item : dto.getItems()) {
			qty += item.getQty().intValue();
		}
		if(transferQty < qty) {
			// 需求数量 < 分配数
			Shift.fatal(StatusCode.GT_ORDER_QTY);
		} else if (transferQty > qty) {
			// 需求数量 > 分配数
			Shift.fatal(StatusCode.NE_ORDER_QTY);
		}
		
		// 查询当前用户权限仓库
		List<Integer> whsIdList = warehouseService.getWareHouseIds(servletRequest);
				
		// 找批次号
		Lotno lotno = lotnoService.getLotnoByIfTransferDtlId(dto.getDtlId(), 0);
		if (lotno == null) {
			Shift.fatal(StatusCode.LOTNO_NULL);
		}
		
		SearchInvRequest dto1 = new SearchInvRequest();
		dto1.setFactory(ifTransferDtl.getFromOrg());
		dto1.setLotno(lotno.getLotno());
		dto1.setSkuId(lotno.getSkuId());
		dto1.setInvAttr(null);
		dto1.setVendorId(null);
		dto1.setQaStatus(null);
        
        // 遍历每个仓库分配多少数量
		Map<String, Integer> processResult = new HashMap<>();
		for (ConfirmInvZoneItemRequest item : dto.getItems()) {
			// 没有这个仓库的权限
			if(!whsIdList.contains(item.getWhsId())) {
				Shift.fatal("不允许分库，没有" + item.getWhsName() + "仓库的权限");
			}
			// 遍历每个库区分配多少数量
			dto1.setWhsId(item.getWhsId());
						
			// 每个仓库分配数量
			int remainingQty = item.getQty().intValue();

			// 校验可用库存是否足够
			int availableQty = 0;
			List<AvailableInvZoneByWhsResponse> availableInvZone = invZoneMapper.getAvailableInvZoneByWhs(dto1);
			for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
				availableQty += invZone.getAvailableQty().intValue();
			}
	        if (remainingQty > availableQty) {
				Shift.fatal(StatusCode.NE_AVAILABLEINVZONE);
			}
	        processResult.put(item.getWhsCode(), remainingQty);
		}
		ifTransferDtl.setProcessStatus(IfTransferDtlProcessStatusEnum.YES.code);
		ifTransferDtl.setProcessResult(JSON.toJSONString(processResult));
		ifTransferDtlMapper.updateById(ifTransferDtl);
		
		// 所有明细状态是否已分库
		QueryWrapper<IfTransferDtl> dtlQueryWrapper = new QueryWrapper<>();
		dtlQueryWrapper.eq("IF_TRANSFER_HEADER_ID", ifTransferDtl.getIfTransferHeaderId());
		dtlQueryWrapper.and(wrapper -> {
			wrapper.isNull("PROCESS_STATUS");
			wrapper.or().eq("PROCESS_STATUS", IfTransferDtlProcessStatusEnum.NO.code);
		});
		if(ifTransferDtlMapper.selectCount(dtlQueryWrapper) == 0) {
			return new Result<>(ifTransferDtl.getIfTransferHeaderId());
		} else {
			return new Result<>();
		}
	}
	
	/**
	 * 取消分配库存
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> cancelInvZone(Integer ifTransferDtlId,
			HttpServletRequest servletRequest) {
		// 调拨中间表明细
		IfTransferDtl ifTransferDtl = ifTransferDtlMapper.selectById(ifTransferDtlId);
		// 调拨中间表主档
		IfTransferHeader ifTransferHeader = ifTransferHeaderMapper.selectById(ifTransferDtl.getIfTransferHeaderId());
		
		if (IfTransferDtlProcessStatusEnum.YES.code != ifTransferDtl.getProcessStatus() ||
				IfTransferProcessStatusEnum.YES.code == ifTransferHeader.getProcessStatus()) {
			Shift.fatal(StatusCode.NOTCAN_CANCEL);
		}
		
		// 置空处理结果和状态
		ifTransferDtlMapper.emptyProcess(ifTransferDtlId);
        return new Result<>();
	}
	
	/**
	 * 拆单
	 * @param ifTransferHeaderId
	 * @param servletRequest
	 * @return
	 * @throws Exception 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<String> split(Integer ifTransferHeaderId,
			HttpServletRequest servletRequest) throws Exception {
		// 调拨中间表主档
		IfTransferHeader ifTransferHeader = ifTransferHeaderMapper.selectById(ifTransferHeaderId);
		
		// 所有明细状态是否已分库
		QueryWrapper<IfTransferDtl> dtlQueryWrapper = new QueryWrapper<>();
		dtlQueryWrapper.eq("IF_TRANSFER_HEADER_ID", ifTransferHeaderId);
		Integer count = ifTransferDtlMapper.selectCount(dtlQueryWrapper);
		
		// 所有调拨中间表明细
		dtlQueryWrapper.eq("PROCESS_STATUS", IfTransferDtlProcessStatusEnum.YES.code);
		List<IfTransferDtl> ifTransferDtlList = ifTransferDtlMapper.selectList(dtlQueryWrapper);
		
		if(IfTransferProcessStatusEnum.YES.code == ifTransferHeader.getProcessStatus() 
				|| count == 0 || count > ifTransferDtlList.size()) {
			Shift.fatal(StatusCode.NOTCAN_SPLIT);
		}
		
		// Map<仓库编码, Map<调拨中间表明细, 分配数量>>
		Map<String, Map<IfTransferDtl, Integer>> transferMap = new HashMap<>();
		// 遍历中间表明细
		for (IfTransferDtl ifTransferDtl : ifTransferDtlList) {
			// Map<仓库编码, 分配数量>
			Map<String, Integer> processResult = JSON.parseObject(ifTransferDtl.getProcessResult(), Map.class);
			for (String whsCode : processResult.keySet()) {
				Map<IfTransferDtl, Integer> dtlMap = transferMap.get(whsCode);
				if(dtlMap == null) {
					dtlMap = new HashMap<>();
					transferMap.put(whsCode, dtlMap);
				}
				dtlMap.put(ifTransferDtl, processResult.get(whsCode));
			}
		}
		
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		// 相关枚举控制属性
		String simpleCodeRule = TransferNoCodeEnum.BETWEEN_FACTORY_TRANSFER.code;
		String transferType = TransferTypeEnum.T03.code;
		String oms = TransferDataSourceEnum.OMS.enumName;
		
		int transferHeaderStatus = TransferHeaderStatusEnum.CREATE.code;
		int transferDtlStatus = TransferDtlStatusEnum.CREATE.code;
		int printFlag = PrintFlagEnum.NO.code;
		int qaStatus = QaStatusEnum.OK.code;	// 默认QA状态
		
		// 默认货主
		DataItemDetailDTO dataItem = basicDataItemDetailApi.getDataItemDetailByPCodeAndName(DEFAULT_OWNER, DEFAULT_OWNER_NAME);
		int ownerId = (dataItem == null || dataItem.getItemValue() == null ? 0 : Integer.parseInt(dataItem.getItemValue()));
		
		// 调拨单明细class
		Class<TransferDtl> transferDtlClass = TransferDtl.class;
		// 批次号class
		Class<Lotno> lotnoClass = Lotno.class;
		
		// 调拨单单据号集合
		List<String> transferNoList = new ArrayList<String>();
		
		QueryWrapper<Warehouse> whsQueryWrapper = new QueryWrapper<>();
		QueryWrapper<Sku> skuQueryWrapper = new QueryWrapper<>();
		// 根据仓库分组遍历
		for (String whsCode : transferMap.keySet()) {
			whsQueryWrapper.clear();
			whsQueryWrapper.eq("WHS_CODE", whsCode);
			Warehouse whs = warehouseMapper.selectOne(whsQueryWrapper);
			
			// 调拨单单据号
			String transferNo = basicSimpleCodeRuleApi.GenerateCode(simpleCodeRule);
			transferNoList.add(transferNo);
			
			// 调拨单表头
			TransferHeader transferHeader = new TransferHeader();
			transferHeader.setTransferNo(transferNo);
			transferHeader.setSourceNo(ifTransferHeader.getBillNo());		// 源单号
			transferHeader.setTransferType(transferType);					// 单据类型
			transferHeader.setFmWhs(whs.getWhsId());						// 来源仓
			transferHeader.setToWhs(whs.getWhsId());						// 目的仓
			transferHeader.setPrintFlag(printFlag);							// 未打印
			transferHeader.setDataSource(oms);								// 数据来源
			transferHeader.setStatus(transferHeaderStatus); 				// 状态（新建）
			transferHeader.setTransferCreateTime(date);
			transferHeader.setErpMoveType(ifTransferHeader.getMovedType()); // 移动类型
			transferHeader.setTransferCreateUser(loginName);
			transferHeader.setPurchsingOrg(ifTransferHeader.getPurchasingOrg());
			transferHeader.setCompanyCode(ifTransferHeader.getCompanyCode());
			transferHeader.setTransferDept(ifTransferHeader.getDept());
			transferHeader.setCreateUser(loginName);
			transferHeader.setCreateTime(date);
			transferHeaderMapper.insert(transferHeader);
			
			// Map<调拨中间表明细, 分配数量>
			Map<IfTransferDtl, Integer> transferDtlMap = transferMap.get(whsCode);
			// 遍历调拨单中间表明细
			Integer transferLineNo = 0;
			for (IfTransferDtl ifTransferDtl : transferDtlMap.keySet()) {
				skuQueryWrapper.clear();
				skuQueryWrapper.eq("SKU_CODE", ifTransferDtl.getMaterialCode());
				Sku sku = skuMapper.selectOne(skuQueryWrapper);
				if(sku == null){
					Shift.fatal("货品\"" + ifTransferDtl.getMaterialCode() + "\"不存在！");
				}
				
				// 调拨单明细
				TransferDtl transferDtl = new TransferDtl();
				transferDtl.setTransferHeaderId(transferHeader.getTransferHeaderId());
				transferDtl.setTransferNo(transferNo);
				transferDtl.setTransferLineNo((++transferLineNo).toString());
				transferDtl.setSourceNo(transferHeader.getSourceNo());
				transferDtl.setSourceLineNo(ifTransferDtl.getBillLineNo());
				transferDtl.setTransferTime(ifTransferDtl.getTransferTime());
				transferDtl.setReturnTime(ifTransferDtl.getReturnTime());
				transferDtl.setOrderQty(transferDtlMap.get(ifTransferDtl));
				transferDtl.setUdf5(ifTransferDtl.getAttribute6());
				transferDtl.setTransitQty(0);
				transferDtl.setCmpQty(0);
				transferDtl.setUnit(sku.getBaseUnit());
				transferDtl.setStatus(transferDtlStatus);
				transferDtl.setCreateUser(loginName);
				transferDtl.setCreateTime(date);
				
				transferDtl.setFmSku(sku.getSkuId());
				transferDtl.setFmOwner(ownerId);
				transferDtl.setFmFactory(ifTransferDtl.getFromOrg());
				transferDtl.setFmQaStatus(qaStatus);
				transferDtl.setFmSoNo(ifTransferDtl.getFromSoNo());
				transferDtl.setFmSoLineNo(ifTransferDtl.getFromSoLineNo());
				transferDtl.setFmPo(ifTransferDtl.getAttribute5());
				
				transferDtl.setToSku(sku.getSkuId());
				transferDtl.setToOwner(ownerId);
				transferDtl.setToFactory(ifTransferDtl.getToOrg());
				transferDtl.setToQaStatus(qaStatus);
				transferDtl.setToSoNo(ifTransferDtl.getToSoNo());
				transferDtl.setToSoLineNo(ifTransferDtl.getToSoLineNo());
				transferDtl.setToPo(ifTransferDtl.getAttribute1());
				
				// 来源批次号
				Lotno fmLotno = lotnoService.getLotnoByIfTransferDtlId(ifTransferDtl.getIfTransferDtlId(), 0);
				if(fmLotno != null) {
					transferDtl.setFmLotno(fmLotno.getLotno());
					for (int i = 1; i < 13; i++) {
						Field lotnoField = lotnoClass.getDeclaredField("lotAttr" + i);
						lotnoField.setAccessible(true);
						Object fmLotnoFieldValue = lotnoField.get(fmLotno);
						
						Method setFmLotAttr = transferDtlClass.getMethod("setFmLotAttr" + i, String.class);
						setFmLotAttr.setAccessible(true);
						setFmLotAttr.invoke(transferDtl, 
								fmLotnoFieldValue == null ? null : fmLotnoFieldValue.toString());
					}
				}
				
				// 目标批次号
				Lotno toLotno = lotnoService.getLotnoByIfTransferDtlId(ifTransferDtl.getIfTransferDtlId(), 1);
				if(toLotno != null) {
					transferDtl.setToLotno(toLotno.getLotno());
					for (int i = 1; i < 13; i++) {
						Field lotnoField = lotnoClass.getDeclaredField("lotAttr" + i);
						lotnoField.setAccessible(true);
						Object toLotnoFieldValue = lotnoField.get(toLotno);
						
						Method setToLotAttr = transferDtlClass.getMethod("setToLotAttr" + i, String.class);
						setToLotAttr.setAccessible(true);
						setToLotAttr.invoke(transferDtl, 
								toLotnoFieldValue == null ? null : toLotnoFieldValue.toString());
					}
				}
				transferDtlMapper.insert(transferDtl);
			}
		}
		
		ifTransferHeader.setProcessStatus(IfTransferProcessStatusEnum.YES.code);
		ifTransferHeader.setProcessResult(JSON.toJSONString(transferNoList));
		ifTransferHeaderMapper.updateById(ifTransferHeader);
		
		String transferNoStr = String.join(",", transferNoList);
		String result = "生成" + transferNoList.size() + "笔调拨单，单号：" + transferNoStr;
        return new Result<String>(result);
	}
}